package com.zbh.uexam.listener;

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zbh.uexam.context.WebContext;
import com.zbh.uexam.domain.Question;
import com.zbh.uexam.domain.Subject;
import com.zbh.uexam.domain.User;
import com.zbh.uexam.domain.enums.GradeLevelEnum;
import com.zbh.uexam.domain.enums.QuestionTypeEnum;
import com.zbh.uexam.exception.BusinessException;
import com.zbh.uexam.service.QuestionService;
import com.zbh.uexam.service.SubjectService;
import com.zbh.uexam.utility.JsonUtil;
import com.zbh.uexam.viewmodel.admin.question.*;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

// 有个很重要的点 DemoDataListener 不能被spring管理，要每次读取excel都要new,然后里面用到spring可以构造方法传进去
public class ExcelDataListener<T> extends AnalysisEventListener<T> {
    private static final Logger LOGGER = LoggerFactory.getLogger(ExcelDataListener.class);
    /**
     * 每隔5条存储数据库，实际使用中可以3000条，然后清理list ，方便内存回收
     */
    List<T> list = new ArrayList<T>();
    /**
     * 假设这个是一个DAO，当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
     */
    private QuestionService questionService;

    private SubjectService subjectService;

    private User user;


    // public ExcelDataListener() {
    //     // 这里是demo，所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
    //     demoDAO = new DemoDAO();
    // }
    /**
     * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
     *
     * @param questionService
     */
    public ExcelDataListener(QuestionService questionService, SubjectService subjectService, User user) {
        this.questionService = questionService;
        this.subjectService = subjectService;
        this.user = user;
    }
    /**
     * 这个每一条数据解析都会来调用
     *
     * @param data
     *            one row value. Is is same as {@link AnalysisContext#readRowHolder()}
     * @param context
     */
    @Override
    public void invoke(T data, AnalysisContext context) {
        LOGGER.info("解析到一条数据:{}", JsonUtil.toJsonStr(data));
        List<Subject> subjects = subjectService.allSubject();
        QuestionEditRequestVM question = new QuestionEditRequestVM();
        JSONObject jsonObject = JSONObject.parseObject(JSON.toJSONString(data));
        List<Subject> collect = subjects.stream().filter(x -> x.getName().equals(jsonObject.getString("subjectName"))).collect(Collectors.toList());
        if (collect.size() == 0) {
            throw new BusinessException("找不到该学科:"+jsonObject.getString("subjectName"));
        }
        List<Question> questions = questionService.selectAll();
        Integer id = jsonObject.getInteger("id");
        if (null != id) {
            if (!questions.stream().map(Question::getId).collect(Collectors.toList()).contains(id)) {
                throw new BusinessException("题目id为"+id+"的题目不存在或已经被删除，无法更新");
            }
        }
        question.setId(id);
        for (Subject subject : collect) {
            if (subject.getLevelName().equals(jsonObject.getString("gradeLevel"))) {
                question.setGradeLevel(subject.getLevel());
                question.setSubjectId(subject.getId());
            }
        }
        if (question.getSubjectId() == null) {
            throw new BusinessException("在该年级:"+jsonObject.getString("gradeLevel")+"找不到该学科:"+jsonObject.getString("subjectName"));

        }
        question.setScore(String.valueOf(jsonObject.getDouble("score")));
        question.setDifficult(jsonObject.getInteger("difficult"));
        question.setTitle(jsonObject.getString("questionTitle"));
        if (jsonObject.containsKey("answer")) {
            question.setCorrect(jsonObject.getString("answer").toUpperCase());
        }
        question.setAnalyze(jsonObject.getString("analysis"));
        List<QuestionEditItemVM> items = new ArrayList<>();
        if (data instanceof SingleChoiceExcelData) {
            SingleChoiceExcelData singleChoiceExcelData = (SingleChoiceExcelData) data;
            question.setQuestionType(QuestionTypeEnum.SingleChoice.getCode());
            items = new ArrayList<>();
            if (StringUtils.isNotBlank(singleChoiceExcelData.getOptionA())) {
                items.add(new QuestionEditItemVM("A", singleChoiceExcelData.getOptionA(), null));
            } else {
                throw new BusinessException("没有A选项");
            }
            if (StringUtils.isNotBlank(singleChoiceExcelData.getOptionA())) {
                items.add(new QuestionEditItemVM("B", singleChoiceExcelData.getOptionA(), null));
            } else {
                throw new BusinessException("没有B选项");
            }
            if (StringUtils.isNotBlank(singleChoiceExcelData.getOptionB())) {
                items.add(new QuestionEditItemVM("C", singleChoiceExcelData.getOptionB(), null));
            } else {
                throw new BusinessException("没有C选项");
            }
            if (StringUtils.isNotBlank(singleChoiceExcelData.getOptionC())) {
                items.add(new QuestionEditItemVM("D", singleChoiceExcelData.getOptionC(), null));
            } else {
                throw new BusinessException("没有D选项");
            }
        } else if (data instanceof MultiChoiceExcelData) {
            question.setQuestionType(QuestionTypeEnum.MultipleChoice.getCode());
            MultiChoiceExcelData multiChoiceExcelData = (MultiChoiceExcelData) data;
            List<String> answerList = new ArrayList<>();
            for(int i = 0; i < multiChoiceExcelData.getAnswer().length(); i++) {
                answerList.add(String.valueOf(multiChoiceExcelData.getAnswer().charAt(i)));
            }
            question.setCorrectArray(answerList);
            items = new ArrayList<>();
            if (StringUtils.isNotBlank(multiChoiceExcelData.getOptionA())) {
                items.add(new QuestionEditItemVM("A", multiChoiceExcelData.getOptionA(), null));
            } else {
                throw new BusinessException("没有A选项");
            }
            if (StringUtils.isNotBlank(multiChoiceExcelData.getOptionB())) {
                items.add(new QuestionEditItemVM("B", multiChoiceExcelData.getOptionB(), null));
            } else {
                throw new BusinessException("没有B选项");
            }
            if (StringUtils.isNotBlank(multiChoiceExcelData.getOptionC())) {
                items.add(new QuestionEditItemVM("C", multiChoiceExcelData.getOptionC(), null));
            } else {
                throw new BusinessException("没有C选项");
            }
            if (StringUtils.isNotBlank(multiChoiceExcelData.getOptionD())) {
                items.add(new QuestionEditItemVM("D", multiChoiceExcelData.getOptionD(), null));
            } else {
                throw new BusinessException("没有D选项");
            }
        } else if (data instanceof JudgmentExcelData) {
            question.setQuestionType(QuestionTypeEnum.TrueFalse.getCode());
            JudgmentExcelData judgmentExcelData = (JudgmentExcelData) data;

            items = new ArrayList<>();
            if (StringUtils.isNotBlank(judgmentExcelData.getOptionA())) {
                items.add(new QuestionEditItemVM("A", judgmentExcelData.getOptionA(), null));
            } else {
                throw new BusinessException("没有A选项");
            }
            if (StringUtils.isNotBlank(judgmentExcelData.getOptionB())) {
                items.add(new QuestionEditItemVM("B", judgmentExcelData.getOptionB(), null));
            } else {
                throw new BusinessException("没有B选项");
            }
        } else if(data instanceof GapFillingExcelData) {
            question.setQuestionType(QuestionTypeEnum.GapFilling.getCode());
            GapFillingExcelData gapFillingExcelData = (GapFillingExcelData) data;
            if (StringUtils.isNotBlank(gapFillingExcelData.getSpaceA())) {
                items.add(new QuestionEditItemVM("1", gapFillingExcelData.getSpaceA(), String.valueOf(gapFillingExcelData.getScore())));
                question.setTitle(question.getTitle().replace("{1}", "<span class=\"gapfilling-span d1a2b6bb-4872-4a64-a114-92f55c34b333\">1</span>"));
            }
            if (StringUtils.isNotBlank(gapFillingExcelData.getSpaceB())) {
                items.add(new QuestionEditItemVM("2", gapFillingExcelData.getSpaceB(), String.valueOf(gapFillingExcelData.getScore())));
                question.setTitle(question.getTitle().replace("{2}", "<span class=\"gapfilling-span d1a2b6bb-4872-4a64-a114-92f55c34b333\">2</span>"));
            }
            if (StringUtils.isNotBlank(gapFillingExcelData.getSpaceC())) {
                items.add(new QuestionEditItemVM("3", gapFillingExcelData.getSpaceC(), String.valueOf(gapFillingExcelData.getScore())));
                question.setTitle(question.getTitle().replace("{3}", "<span class=\"gapfilling-span d1a2b6bb-4872-4a64-a114-92f55c34b333\">3</span>"));
            }
            if (StringUtils.isNotBlank(gapFillingExcelData.getSpaceD())) {
                items.add(new QuestionEditItemVM("4", gapFillingExcelData.getSpaceD(), String.valueOf(gapFillingExcelData.getScore())));
                question.setTitle(question.getTitle().replace("{4}", "<span class=\"gapfilling-span d1a2b6bb-4872-4a64-a114-92f55c34b333\">4</span>"));
            }
            if (items.size() == 0) {
                throw new BusinessException("填空题至少有一个空");
            }
            double sum = items.stream().mapToDouble(x -> Double.parseDouble(x.getScore())).sum();
            question.setCorrectArray(items.stream().map(QuestionEditItemVM::getContent).collect(Collectors.toList()));
            question.setScore(String.valueOf(sum));
        } else if (data instanceof ShortAnswerExcelData) {
            question.setQuestionType(QuestionTypeEnum.ShortAnswer.getCode());
        }
        question.setItems(items);
        if (null == question.getId()) {
            questionService.insertFullQuestion(question, user.getId());
        } else {
            questionService.updateFullQuestion(question);
        }

    }
    /**
     * 所有数据解析完成了 都会来调用
     *
     * @param context
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        // 这里也要保存数据，确保最后遗留的数据也存储到数据库
        saveData();
        LOGGER.info("所有数据解析完成！");
    }
    /**
     * 加上存储数据库
     */
    private void saveData() {
        LOGGER.info("{}条数据，开始存储数据库！", list.size());

        LOGGER.info("存储数据库成功！");
    }
}